/**************************************************************************
 * @file serial_protocol_demo.c
 * @author BryanHe(贺璧) (532352406@qq.com)
 * @brief 
 * @version 0.1
 * @date 2025-04-08
 * 
 * @copyright Copyright (c) 2025
 * 
 *************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>  // 用于非阻塞输入检测
#include "../inc/serial_protocol.h"
#include "serial_protocol_demo.h"

#define MAX_DATA          100
#define INPUT_BUFFER_SIZE 256

// 共享数据结构
typedef struct {
    int data;
    HANDLE hDataReadyEvent;  // 数据就绪事件
    HANDLE hMutex;           // 数据互斥锁

    uint8_t dat_pipline[USR_D_PACK_MAX_PACKAGE_LEN];
    uint16_t dat_pip_len;
    uint8_t send_pkg[USR_D_PACK_MAX_PACKAGE_LEN];
    uint8_t rec_buf[USR_D_PACK_MAX_DAT_PAYLOAD];
    uint8_t rec_index;

} ThreadChannel;

// 全局退出标志
volatile BOOL g_exit = FALSE;
ThreadChannel* channelAtoB;
ThreadChannel* channelBtoA;
/***********************************Thread A processing****************************************** */

static CommandStatus USR_CMD_FUN_NAME_MAKE(USR_CMD_SET_VOL)(const uint8_t* params, uint8_t len, uint8_t* response,uint16_t *response_len){
    SP_LOG("A VOL:\n");
    SP_LOG_RAW(params,len);
    SP_LOG("\n");
    *response_len = 0;

    return STATUS_SUCCESS;
}
static CommandStatus USR_CMD_FUN_NAME_MAKE(USR_CMD_GET_TX_INFOR)(const uint8_t* params, uint8_t len, uint8_t* response,uint16_t *response_len){
    SP_LOG("USR_CMD_GET_TX_INFOR:\n");

    /*ACK TX version V1.1*/
    response[0] = 0x01;//version major 
    response[1] = 0x01;//version minor

    *response_len = 2; //ack data length

    return STATUS_SUCCESS;
}
static CommandStatus USR_CMD_FUN_NAME_MAKE(USR_CMD_GET_RX_INFOR)(const uint8_t* params, uint8_t len, uint8_t* response,uint16_t *response_len){
    SP_LOG("USR_CMD_GET_RX_INFOR:\n");

     /*ACK RX version V1.1*/
     response[0] = 0x01;//version major 
     response[1] = 0x01;//version minor
 
     *response_len = 2; //ack data length

    return STATUS_SUCCESS;
}

const UserCommand tak_A_cmd_table[]={
    FORMAT_USR_CMD_ITEM(USR_CMD_SET_VOL),
    FORMAT_USR_CMD_ITEM(USR_CMD_GET_TX_INFOR),
    FORMAT_USR_CMD_ITEM(USR_CMD_GET_RX_INFOR),
};


static int A_serial_send(uint8_t *p_buf,uint16_t send_len){
    memcpy(channelAtoB->dat_pipline,p_buf,send_len);
    channelAtoB->dat_pip_len = send_len;
    SetEvent(channelAtoB->hDataReadyEvent);
}

static void A_serial_ack_cb(CommandCode cmd, CommandStatus status, const uint8_t* params, uint8_t len) {
    SP_LOG("A ack:%x,%x\n", cmd, status);
    switch (cmd) {
        case USR_CMD_GET_TX_INFOR:
            SP_LOG("TX-Ver:V%d.%x\n", params[0],params[1]);
            break;
        case USR_CMD_GET_RX_INFOR:
            SP_LOG("RX-Ver:V%d.%x\n", params[0],params[1]);
            break;

        default:
            break;
    }
}

const uint8_t test_get_protocol_infor[]={CMD_GET_INFO,0x78,0x55,0xaa,0x5a,0x7e};

const uint8_t test_escape_infor[]={CMD_SET_CONFIG,0x55,0xaa,0x7e,0x0a,0x37,0x55};

const uint8_t test_set_vol_infor[]={USR_CMD_SET_VOL,30/*vol value*/};
// serial_protocol_send(&A_serial_handler, test_set_vol_infor, sizeof(test_set_vol_infor),A_serial_ack_cb);

// 线程A处理函数
DWORD WINAPI ThreadAProc(LPVOID lpParam) {
    ProtocolHandler A_serial_handler;
    DWORD bytesRead;
    INPUT_RECORD inputRecord;
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);

    serial_protocol_init(&A_serial_handler,tak_A_cmd_table,sizeof(tak_A_cmd_table)/sizeof(UserCommand),A_serial_send,1);
    // 发送初始数据
    WaitForSingleObject(channelAtoB->hMutex, INFINITE);
    ReleaseMutex(channelAtoB->hMutex);
    // SetEvent(channelAtoB->hDataReadyEvent);

    while (!g_exit) {
        // 检查控制台输入事件
        if (WaitForSingleObject(hStdin, 1) == WAIT_OBJECT_0) {
            ReadConsoleInput(hStdin, &inputRecord, 1, &bytesRead);
            
            if (inputRecord.EventType == KEY_EVENT && inputRecord.Event.KeyEvent.bKeyDown) {
                // 处理回车键
                if (inputRecord.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) {
                    SP_LOG("cmd:%s\n",channelAtoB->rec_buf);  // 换行显示
                    if(!strcmp(channelAtoB->rec_buf,"get_p_infor")){
                        serial_protocol_send(&A_serial_handler, test_get_protocol_infor, sizeof(test_get_protocol_infor),A_serial_ack_cb);
                    }else if(!strcmp(channelAtoB->rec_buf,"set_vol")){
                        serial_protocol_send(&A_serial_handler, test_set_vol_infor, sizeof(test_set_vol_infor),A_serial_ack_cb);
                    }else if(!strcmp(channelAtoB->rec_buf,"test_es")){
                        serial_protocol_send(&A_serial_handler, test_escape_infor, sizeof(test_escape_infor),A_serial_ack_cb);
                    }

                    memset(channelAtoB->rec_buf,0,sizeof(channelAtoB->rec_buf));

                    channelAtoB->rec_index = 0;
                }
                else if (inputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) {
                    g_exit = 1;
                    SP_LOG("exit\n");  // 换行显示
                }else {// 处理普通字符
                    char ch = inputRecord.Event.KeyEvent.uChar.AsciiChar;
                    
                    if (ch != 0) {
                        SP_LOG("%d->%c", channelAtoB->rec_index,ch);  // 回显输入
                        channelAtoB->rec_buf[channelAtoB->rec_index++] = ch;
                        if(channelAtoB->rec_index>=USR_D_PACK_MAX_DAT_PAYLOAD)channelAtoB->rec_index=0;
                    }
                }
            }
        }

        DWORD dwWait = WaitForSingleObject(channelBtoA->hDataReadyEvent, 1);
        if (dwWait == WAIT_OBJECT_0) {
            // 读取数据
            serial_protocol_receive(&A_serial_handler, channelBtoA->dat_pipline, channelBtoA->dat_pip_len);
        }

        serial_protocol_processing(&A_serial_handler);

    }
    return 0;
}
/********************************************************************************************** */

/*********************************Thread B processing************************************************************* */

static CommandStatus B_vol_handler(const uint8_t* params, uint8_t len, uint8_t* response,uint16_t *response_len){
    SP_LOG("B VOL:\n");
    SP_LOG_RAW(params,len);
    SP_LOG("\n");
    *response_len = 0;

    return STATUS_SUCCESS;
}
static CommandStatus B_get_infor_handler(const uint8_t* params, uint8_t len, uint8_t* response,uint16_t *response_len){
    SP_LOG("get infor:\n");
    SP_LOG_RAW(params,len);
    SP_LOG("\n");
    /*version V1.01*/
    response[0]=0x01,
    response[1]=0x01,

    *response_len = 2;

    return STATUS_SUCCESS;
}
static int B_serial_send(uint8_t *p_buf,uint16_t send_len){
    memcpy(channelBtoA->dat_pipline,p_buf,send_len);
    channelBtoA->dat_pip_len = send_len;
    SetEvent(channelBtoA->hDataReadyEvent);
}

static void B_serial_ack_cb(CommandCode cmd, CommandStatus status,const uint8_t* params, uint8_t len){
    SP_LOG("B ack:%x,%x\n",cmd,status);
    SP_LOG_RAW(params,len);

}

const UserCommand tak_B_cmd_table[]={
    {.code = FORMAT_USR_CMD_CODE(USR_CMD_SET_VOL),.handler = B_vol_handler},
    {.code = FORMAT_USR_CMD_CODE(CMD_GET_INFO),.handler = B_get_infor_handler}
};

// 线程B处理函数（发送偶数）
DWORD WINAPI ThreadBProc(LPVOID lpParam) {
    ProtocolHandler B_serial_handler;

    serial_protocol_init(&B_serial_handler,tak_B_cmd_table,sizeof(tak_B_cmd_table)/sizeof(UserCommand),B_serial_send,1);

    while (!g_exit) {
        // 等待A的数据
        DWORD dwWait = WaitForSingleObject(channelAtoB->hDataReadyEvent, 1);
        if (dwWait == WAIT_OBJECT_0) {
            // 读取数据
            serial_protocol_receive(&B_serial_handler, channelAtoB->dat_pipline, channelAtoB->dat_pip_len);
        }
        serial_protocol_processing(&B_serial_handler);
    }
    return 0;
}
/*************************************************************************************************** */
int main() {
    // 创建两个通信通道
    ThreadChannel channels[2] = {0};
    
    channels[0].hDataReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    channels[0].hMutex = CreateMutex(NULL, FALSE, NULL);
    channels[1].hDataReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    channels[1].hMutex = CreateMutex(NULL, FALSE, NULL);

    channelAtoB = &channels[0];
    channelBtoA = &channels[1];    
    // 创建线程
    HANDLE hThreads[2] = {
        CreateThread(NULL, 0, ThreadAProc, channels, 0, NULL),
        CreateThread(NULL, 0, ThreadBProc, channels, 0, NULL)
    };

    SP_LOG("Press Esc to exit...%d,%d,%d\n",1,2,3);
    // SP_LOG();
    // getchar();
    
    while(!g_exit){
    }
    g_exit = TRUE;
    // 等待线程结束
    WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);

    // 清理资源
    for (int i = 0; i < 2; i++) {
        CloseHandle(channels[i].hDataReadyEvent);
        CloseHandle(channels[i].hMutex);
    }

    return 0;
}